"""
性能监控模块

实现系统性能指标监控、分析和优化建议
"""

import time
import psutil
import asyncio
import threading
from typing import Dict, List, Any, Optional, Callable
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from collections import defaultdict, deque
from .interfaces import IPerformanceMonitor
from .unified_core import unified_logger, event_bus, EventTypes


@dataclass
class PerformanceMetric:
    """性能指标数据结构"""
    name: str
    value: float
    unit: str
    timestamp: datetime
    tags: Dict[str, str] = field(default_factory=dict)


@dataclass
class SystemMetrics:
    """系统指标"""
    cpu_percent: float
    memory_percent: float
    memory_used: float
    memory_available: float
    disk_usage: float
    network_io: Dict[str, int]
    process_count: int
    timestamp: datetime


class PerformanceTimer:
    """性能计时器"""
    
    def __init__(self, name: str, monitor: 'PerformanceMonitor'):
        self.name = name
        self.monitor = monitor
        self.start_time = None
        
    def __enter__(self):
        self.start_time = time.perf_counter()
        return self
        
    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.start_time:
            duration = time.perf_counter() - self.start_time
            # 同步记录指标，避免事件循环问题
            try:
                loop = asyncio.get_running_loop()
                asyncio.create_task(
                    self.monitor.record_metric(
                        f"{self.name}.duration",
                        duration * 1000,  # 转换为毫秒
                        "ms"
                    )
                )
            except RuntimeError:
                # 没有运行的事件循环，直接同步记录
                metric = PerformanceMetric(
                    name=f"{self.name}.duration",
                    value=duration * 1000,
                    unit="ms",
                    timestamp=datetime.now()
                )
                self.monitor._metrics[metric.name].append(metric)


class PerformanceMonitor(IPerformanceMonitor):
    """性能监控器"""
    
    def __init__(self, max_metrics: int = 10000):
        self.logger = unified_logger.get_logger("performance")
        self._metrics: Dict[str, deque] = defaultdict(lambda: deque(maxlen=1000))
        self._system_metrics: deque = deque(maxlen=1000)
        self._max_metrics = max_metrics
        self._monitoring = False
        self._monitor_task = None
        self._alert_thresholds = {
            'cpu_percent': 80.0,
            'memory_percent': 85.0,
            'disk_usage': 90.0,
            'response_time': 1000.0  # ms
        }
        self._performance_counters = defaultdict(int)
        self._lock = asyncio.Lock()
        
    async def start_monitoring(self, interval: float = 5.0) -> None:
        """开始性能监控"""
        if self._monitoring:
            return
            
        self._monitoring = True
        self._monitor_task = asyncio.create_task(
            self._monitor_loop(interval)
        )
        
        self.logger.info(f"性能监控已启动，监控间隔: {interval}秒")
        
        await event_bus.emit(
            EventTypes.PERFORMANCE_METRIC,
            {"component": "performance_monitor", "status": "started"}
        )
    
    async def stop_monitoring(self) -> None:
        """停止性能监控"""
        self._monitoring = False
        
        if self._monitor_task:
            self._monitor_task.cancel()
            try:
                await self._monitor_task
            except asyncio.CancelledError:
                pass
            
        self.logger.info("性能监控已停止")
        
        await event_bus.emit(
            EventTypes.PERFORMANCE_METRIC,
            {"component": "performance_monitor", "status": "stopped"}
        )
    
    async def _monitor_loop(self, interval: float) -> None:
        """监控循环"""
        while self._monitoring:
            try:
                # 收集系统指标
                system_metrics = await self._collect_system_metrics()
                
                async with self._lock:
                    self._system_metrics.append(system_metrics)
                
                # 检查告警阈值
                await self._check_alerts(system_metrics)
                
                # 记录性能计数器
                await self._record_performance_counters()
                
                await asyncio.sleep(interval)
                
            except Exception as e:
                self.logger.error(f"性能监控循环出错: {e}", exc_info=True)
                await asyncio.sleep(interval)
    
    async def _collect_system_metrics(self) -> SystemMetrics:
        """收集系统指标"""
        try:
            # CPU使用率
            cpu_percent = psutil.cpu_percent(interval=1)
            
            # 内存使用情况
            memory = psutil.virtual_memory()
            
            # 磁盘使用情况
            disk = psutil.disk_usage('/')
            
            # 网络IO
            network = psutil.net_io_counters()
            network_io = {
                'bytes_sent': network.bytes_sent,
                'bytes_recv': network.bytes_recv,
                'packets_sent': network.packets_sent,
                'packets_recv': network.packets_recv
            }
            
            # 进程数量
            process_count = len(psutil.pids())
            
            return SystemMetrics(
                cpu_percent=cpu_percent,
                memory_percent=memory.percent,
                memory_used=memory.used / (1024**3),  # GB
                memory_available=memory.available / (1024**3),  # GB
                disk_usage=disk.percent,
                network_io=network_io,
                process_count=process_count,
                timestamp=datetime.now()
            )
            
        except Exception as e:
            self.logger.error(f"收集系统指标失败: {e}")
            raise
    
    async def _check_alerts(self, metrics: SystemMetrics) -> None:
        """检查告警阈值"""
        alerts = []
        
        if metrics.cpu_percent > self._alert_thresholds['cpu_percent']:
            alerts.append({
                'type': 'cpu_high',
                'value': metrics.cpu_percent,
                'threshold': self._alert_thresholds['cpu_percent'],
                'message': f"CPU使用率过高: {metrics.cpu_percent:.1f}%"
            })
        
        if metrics.memory_percent > self._alert_thresholds['memory_percent']:
            alerts.append({
                'type': 'memory_high',
                'value': metrics.memory_percent,
                'threshold': self._alert_thresholds['memory_percent'],
                'message': f"内存使用率过高: {metrics.memory_percent:.1f}%"
            })
        
        if metrics.disk_usage > self._alert_thresholds['disk_usage']:
            alerts.append({
                'type': 'disk_high',
                'value': metrics.disk_usage,
                'threshold': self._alert_thresholds['disk_usage'],
                'message': f"磁盘使用率过高: {metrics.disk_usage:.1f}%"
            })
        
        for alert in alerts:
            self.logger.warning(alert['message'])
            await event_bus.emit(
                EventTypes.SYSTEM_ERROR,
                {
                    "alert_type": alert['type'],
                    "value": alert['value'],
                    "threshold": alert['threshold'],
                    "message": alert['message']
                }
            )
    
    async def _record_performance_counters(self) -> None:
        """记录性能计数器"""
        for name, count in self._performance_counters.items():
            await self.record_metric(f"counter.{name}", count, "count")
        
        # 重置计数器
        self._performance_counters.clear()
    
    async def record_metric(self, name: str, value: float, unit: str,
                          tags: Optional[Dict[str, str]] = None) -> None:
        """记录性能指标"""
        metric = PerformanceMetric(
            name=name,
            value=value,
            unit=unit,
            timestamp=datetime.now(),
            tags=tags or {}
        )
        
        async with self._lock:
            self._metrics[name].append(metric)
        
        # 检查响应时间告警
        if 'response_time' in name or 'duration' in name:
            if value > self._alert_thresholds['response_time']:
                self.logger.warning(f"响应时间过长: {name} = {value:.2f}ms")
                await event_bus.emit(
                    EventTypes.SYSTEM_ERROR,
                    {
                        "alert_type": "response_time_high",
                        "metric": name,
                        "value": value,
                        "threshold": self._alert_thresholds['response_time']
                    }
                )
    
    def timer(self, name: str) -> PerformanceTimer:
        """创建性能计时器"""
        return PerformanceTimer(name, self)
    
    def increment_counter(self, name: str, value: int = 1) -> None:
        """增加计数器"""
        self._performance_counters[name] += value
    
    async def get_metrics(self, name: str, 
                         start_time: Optional[datetime] = None,
                         end_time: Optional[datetime] = None) -> List[PerformanceMetric]:
        """获取性能指标"""
        async with self._lock:
            metrics = list(self._metrics.get(name, []))
        
        if start_time or end_time:
            filtered_metrics = []
            for metric in metrics:
                if start_time and metric.timestamp < start_time:
                    continue
                if end_time and metric.timestamp > end_time:
                    continue
                filtered_metrics.append(metric)
            return filtered_metrics
        
        return metrics
    
    async def get_system_metrics(self, 
                               start_time: Optional[datetime] = None,
                               end_time: Optional[datetime] = None) -> List[SystemMetrics]:
        """获取系统指标"""
        async with self._lock:
            metrics = list(self._system_metrics)
        
        if start_time or end_time:
            filtered_metrics = []
            for metric in metrics:
                if start_time and metric.timestamp < start_time:
                    continue
                if end_time and metric.timestamp > end_time:
                    continue
                filtered_metrics.append(metric)
            return filtered_metrics
        
        return metrics
    
    async def get_metric_statistics(self, name: str,
                                  window_minutes: int = 60) -> Dict[str, float]:
        """获取指标统计信息"""
        end_time = datetime.now()
        start_time = end_time - timedelta(minutes=window_minutes)
        
        metrics = await self.get_metrics(name, start_time, end_time)
        
        if not metrics:
            return {}
        
        values = [m.value for m in metrics]
        
        return {
            'count': len(values),
            'min': min(values),
            'max': max(values),
            'avg': sum(values) / len(values),
            'latest': values[-1] if values else 0
        }
    
    async def get_performance_report(self) -> Dict[str, Any]:
        """获取性能报告"""
        report = {
            'timestamp': datetime.now().isoformat(),
            'system_metrics': {},
            'application_metrics': {},
            'alerts': [],
            'recommendations': []
        }
        
        # 系统指标统计
        if self._system_metrics:
            latest_system = self._system_metrics[-1]
            report['system_metrics'] = {
                'cpu_percent': latest_system.cpu_percent,
                'memory_percent': latest_system.memory_percent,
                'memory_used_gb': latest_system.memory_used,
                'memory_available_gb': latest_system.memory_available,
                'disk_usage_percent': latest_system.disk_usage,
                'process_count': latest_system.process_count
            }
        
        # 应用指标统计
        for metric_name in self._metrics.keys():
            stats = await self.get_metric_statistics(metric_name)
            if stats:
                report['application_metrics'][metric_name] = stats
        
        # 生成优化建议
        recommendations = await self._generate_recommendations()
        report['recommendations'] = recommendations
        
        return report
    
    async def _generate_recommendations(self) -> List[str]:
        """生成性能优化建议"""
        recommendations = []
        
        if self._system_metrics:
            latest = self._system_metrics[-1]
            
            if latest.cpu_percent > 70:
                recommendations.append("CPU使用率较高，建议优化计算密集型操作或增加CPU资源")
            
            if latest.memory_percent > 80:
                recommendations.append("内存使用率较高，建议优化内存使用或增加内存资源")
            
            if latest.disk_usage > 85:
                recommendations.append("磁盘使用率较高，建议清理日志文件或扩展存储空间")
        
        # 检查响应时间
        for metric_name in self._metrics.keys():
            if 'duration' in metric_name or 'response_time' in metric_name:
                stats = await self.get_metric_statistics(metric_name)
                if stats and stats.get('avg', 0) > 500:  # 500ms
                    recommendations.append(f"操作 {metric_name} 响应时间较长，建议优化相关逻辑")
        
        return recommendations
    
    def set_alert_threshold(self, metric: str, threshold: float) -> None:
        """设置告警阈值"""
        self._alert_thresholds[metric] = threshold
        self.logger.info(f"设置告警阈值: {metric} = {threshold}")
    
    async def clear_metrics(self, metric_name: Optional[str] = None) -> None:
        """清空指标数据"""
        async with self._lock:
            if metric_name:
                if metric_name in self._metrics:
                    self._metrics[metric_name].clear()
                    self.logger.info(f"已清空指标: {metric_name}")
            else:
                self._metrics.clear()
                self._system_metrics.clear()
                self.logger.info("已清空所有指标数据")


# 全局性能监控器实例
performance_monitor = PerformanceMonitor()


class PerformanceDecorator:
    """性能监控装饰器"""
    
    @staticmethod
    def monitor_performance(metric_name: str = None):
        """性能监控装饰器"""
        def decorator(func):
            name = metric_name or f"{func.__module__}.{func.__name__}"
            
            if asyncio.iscoroutinefunction(func):
                async def async_wrapper(*args, **kwargs):
                    async with performance_monitor.timer(name):
                        result = await func(*args, **kwargs)
                    performance_monitor.increment_counter(f"{name}.calls")
                    return result
                return async_wrapper
            else:
                def sync_wrapper(*args, **kwargs):
                    with performance_monitor.timer(name):
                        result = func(*args, **kwargs)
                    performance_monitor.increment_counter(f"{name}.calls")
                    return result
                return sync_wrapper
        return decorator
    
    @staticmethod
    def track_errors(metric_name: str = None):
        """错误跟踪装饰器"""
        def decorator(func):
            name = metric_name or f"{func.__module__}.{func.__name__}"
            
            if asyncio.iscoroutinefunction(func):
                async def async_wrapper(*args, **kwargs):
                    try:
                        return await func(*args, **kwargs)
                    except Exception as e:
                        performance_monitor.increment_counter(f"{name}.errors")
                        await performance_monitor.record_metric(
                            f"{name}.error_rate", 1, "count",
                            {"error_type": type(e).__name__}
                        )
                        raise
                return async_wrapper
            else:
                def sync_wrapper(*args, **kwargs):
                    try:
                        return func(*args, **kwargs)
                    except Exception as e:
                        performance_monitor.increment_counter(f"{name}.errors")
                        asyncio.create_task(
                            performance_monitor.record_metric(
                                f"{name}.error_rate", 1, "count",
                                {"error_type": type(e).__name__}
                            )
                        )
                        raise
                return sync_wrapper
        return decorator


# 便捷函数
async def start_performance_monitoring(interval: float = 5.0) -> None:
    """启动性能监控"""
    await performance_monitor.start_monitoring(interval)


async def stop_performance_monitoring() -> None:
    """停止性能监控"""
    await performance_monitor.stop_monitoring()


def monitor_performance(metric_name: str = None):
    """性能监控装饰器"""
    return PerformanceDecorator.monitor_performance(metric_name)


def track_errors(metric_name: str = None):
    """错误跟踪装饰器"""
    return PerformanceDecorator.track_errors(metric_name)